package com.api.aiyh_pcn.fadada.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.ws.rs.core.StreamingOutput;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;

import com.alibaba.fastjson.JSONObject;
import com.api.aiyh_pcn.fadada.dao.FaDDServiceMapping;
import com.api.aiyh_pcn.fadada.entity.FaDaDaConfigDTO;
import com.api.aiyh_pcn.fadada.service.IFaDDService;
import com.api.aiyh_pcn.fadada.util.FaDDRequestUtils;
import com.api.aiyh_pcn.fadada.vo.TableFieldMappingVO;
import com.fasterxml.jackson.core.JsonProcessingException;

import aiyh.utils.Util;
import aiyh.utils.entity.ApiConfigDetailDTO;
import aiyh.utils.entity.ApiConfigMainDTO;
import aiyh.utils.httpUtil.ResponeVo;
import aiyh.utils.zwl.common.ToolUtil;
import weaver.conn.RecordSet;
import weaver.workflow.workflow.WorkflowVersion;

/**
 * @author EBU7-dev1-ayh
 * @create 2021/9/30 0030 11:12 service
 */
public class FaDDServiceImpl implements IFaDDService {
    private final FaDDServiceMapping faDDServiceMapping = new FaDDServiceMapping();
    private final ToolUtil toolUtil = new ToolUtil();
    // private final String MAIN_TABLE = "formtable_main_17";

    @Override
    public Map<String, Object> getConfigParam(String workflowId) {
        FaDaDaConfigDTO faDaDaConfigDTO = faDDServiceMapping.queryConfig(workflowId, 0);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfig(faDaDaConfigDTO.getParamsConfig());
        List<TableFieldMappingVO> tableFieldMappingVOS = new ArrayList<>();
        List<ApiConfigDetailDTO> details = apiConfigMainDTO.getDetails();
        for (ApiConfigDetailDTO detail : details) {
            TableFieldMappingVO tableFieldMappingVO = new TableFieldMappingVO();
            String tableName = "";
            String fieldName = "";
            int id = detail.getId();
            String table = detail.getTablename();
            if (!table.contains("_dt")) {
                // 表示字段属于主表
                tableName = "main";
            } else {
                // 字段属于明细表
                String dt = table.substring(table.indexOf("_dt") + 3);
                tableName = "detail_" + dt;
            }
            tableFieldMappingVO.setTableName(tableName);
            tableFieldMappingVO.setId(id);
            int changeRule = detail.getChangeRule();
            if (changeRule == 0) {
                // 不转换，需要获取到流程字段，前端获取流程字段对应的值
                fieldName = detail.getWorkflowField();
                tableFieldMappingVO.setField(fieldName);
                tableFieldMappingVOS.add(tableFieldMappingVO);
            } else if (changeRule == 2) {
                // 流程字段值，与不转换一至
                fieldName = detail.getWorkflowField();
                tableFieldMappingVO.setField(fieldName);
                tableFieldMappingVOS.add(tableFieldMappingVO);
            }
            if (changeRule == 7 || changeRule == 6) {
                // 7 自定义SQL，与流程转SQL一样
                List<TableFieldMappingVO> tableFieldMappingVOList = new ArrayList<>();
                // 6 流程字段转SQL，需要获取SQL中的字段变量，前端通过字段变量获取值
                // 解析SQL
                Map<String, List<String>> result = Util.parsingSq2Map(detail.getParamValue());
                for (Map.Entry<String, List<String>> entry : result.entrySet()) {
                    for (String field : entry.getValue()) {
                        TableFieldMappingVO tf = new TableFieldMappingVO();
                        tf.setTableName(entry.getKey());
                        tf.setField(field);
                        tf.setId(id);
                        tableFieldMappingVOList.add(tf);
                    }
                }
                tableFieldMappingVOS.addAll(tableFieldMappingVOList);
            }
            if (detail.getParamType() == 4) {
                // 数组类型的，需要解析数组sql
                List<TableFieldMappingVO> tableFieldMappingVOList = new ArrayList<>();
                Map<String, List<String>> result = Util.parsingSq2Map(detail.getArraySql());
                for (Map.Entry<String, List<String>> entry : result.entrySet()) {
                    for (String field : entry.getValue()) {
                        TableFieldMappingVO tf = new TableFieldMappingVO();
                        tf.setTableName(entry.getKey());
                        tf.setField(field);
                        tf.setId(id);
                        tableFieldMappingVOList.add(tf);
                    }
                }
                tableFieldMappingVOS.addAll(tableFieldMappingVOList);
            }
        }
        List<TableFieldMappingVO> doDeWeight =
            Util.deWeight(tableFieldMappingVOS, e -> e.getTableName() + e.getField());
        Map<String, Object> map = new HashMap<>();
        map.put("tableFieldMappings", doDeWeight);
        String checkSource = faDaDaConfigDTO.getCheckSource();
        String sourceTable;
        if (!checkSource.contains("_dt")) {
            // 表示字段属于主表
            sourceTable = "main";
            map.put("isMain", true);
        } else {
            // 字段属于明细表
            String dt = checkSource.substring(checkSource.indexOf("_dt") + 3);
            sourceTable = "detail_" + dt;
            map.put("isMain", false);
        }
        map.put("sourceTable", sourceTable);
        return map;
    }

    @Override
    public Map<String, Object> checkCertification(Map<String, Object> params) {
        Map<String, Object> resultMap = new HashMap<>();
        String workflowId = String.valueOf(params.get("workflowId"));
        FaDaDaConfigDTO faDaDaConfigDTO = faDDServiceMapping.queryConfig(workflowId, 0);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfigTree(faDaDaConfigDTO.getParamsConfig());
        List<Map<String, Object>> dataArr = (List<Map<String, Object>>)params.get("dataArr");
        List<ApiConfigDetailDTO> details = apiConfigMainDTO.getDetails();
        List<Map<String, Object>> datas = objectAndListHandle(details, dataArr);
        List<Map<String, Object>> errorList = new ArrayList<>();
        List<Map<String, Object>> nonsupportList = new ArrayList<>();
        for (Map<String, Object> data : datas) {
            System.out.println(JSONObject.toJSONString(data));
            Map<String, Object> result = FaDDRequestUtils.checkCompanyInfo(data);
            if (result == null) {
                // 未查询到数据
                errorList.add(data);
            } else {
                if ("1001005".equals(String.valueOf(result.get("code")))
                    || !"200".equals(String.valueOf(result.get("code")))) {
                    // 企业信息不存在或者未认证
                    nonsupportList.add(data);
                }
            }
        }
        if (errorList.size() == 0 && nonsupportList.size() == 0) {
            // 所有的都通过
            resultMap.put("allPass", true);
        } else {
            resultMap.put("allPass", false);
            resultMap.put("errorList", errorList);
            resultMap.put("nonsupportList", nonsupportList);
        }
        return resultMap;
    }

    private List<Map<String, Object>> objectAndListHandle(List<ApiConfigDetailDTO> treeList,
        List<Map<String, Object>> dataArr) {
        List<Map<String, Object>> params = new ArrayList<>();
        for (Map<String, Object> dataMap : dataArr) {
            Map<String, Object> param = new HashMap<>();
            for (ApiConfigDetailDTO apiConfigDetailDTO : treeList) {
                Object value;
                if (apiConfigDetailDTO.getParamType() == 3) {
                    Map<String, Object> map = new HashMap<>();
                    // object类型
                    for (ApiConfigDetailDTO child : apiConfigDetailDTO.getChildren()) {
                        if (child.getChildren() == null || child.getChildren().size() == 0) {
                            // handleChild(child.getChildren(), dataMap)
                            map.put(child.getParamName(), changeRuleHandle(child, dataMap));
                        } else {
                            map.put(child.getParamName(), handleChild(child.getChildren(), dataMap));
                        }
                    }
                    value = map;
                } else if (apiConfigDetailDTO.getParamType() == 4) {
                    String sql = apiConfigDetailDTO.getArraySql();
                    String parsingSq = Util.parsingSq(sql, dataMap);
                    // list类型
                    if (parsingSq.contains("delete") || parsingSq.contains("update") || parsingSq.contains("exec")
                        || parsingSq.contains("drop") || parsingSq.contains("truncate")) {
                        value = new ArrayList<>();
                    } else {
                        RecordSet rs = new RecordSet();
                        rs.executeQuery(parsingSq.replace("ｓｅｌｅｃｔ", "select"));
                        value = Util.recordeSet2Array(rs, String.class);
                    }
                } else {
                    value = changeRuleHandle(apiConfigDetailDTO, dataMap);
                }
                param.put(apiConfigDetailDTO.getParamName(), value);
            }
            params.add(param);
        }
        return params;
    }

    private Object handleChild(List<ApiConfigDetailDTO> children, Map<String, Object> dataMap) {
        Map<String, Object> params = new HashMap<>();
        for (ApiConfigDetailDTO child : children) {
            Object value;
            if (child.getChildren() != null) {
                value = handleChild(child.getChildren(), dataMap);
            } else {
                value = changeRuleHandle(child, dataMap);
            }
            params.put(child.getParamName(), value);
        }
        return params;
    }

    private Object changeRuleHandle(ApiConfigDetailDTO apiConfigDetailDTO, Map<String, Object> dataMap) {
        Object value;
        String tableName;
        String table;
        String sql;
        String resultSql;
        // 判断参数的转换规则
        switch (apiConfigDetailDTO.getChangeRule()) {
            case 0:
                // 不转换
            case 2:
                // 流程字段值
                table = apiConfigDetailDTO.getTablename();
                if (!table.contains("_dt")) {
                    // 表示字段属于主表
                    tableName = "main";
                } else {
                    // 字段属于明细表
                    String dt = table.substring(table.indexOf("_dt") + 3);
                    tableName = "detail_" + dt;
                }
                value = dataMap.get(tableName + "." + apiConfigDetailDTO.getWorkflowField());
                break;
            case 1:
                // 固定值
                value = apiConfigDetailDTO.getParamValue();
                break;
            case 3:
                // 系统日期
                value = Util.getTime("yyyy-MM-dd");
                break;
            case 4:
                // 系统时间
                value = Util.getTime("HH:mm:ss");
                break;
            case 5:
                // 系统日期-时间
                value = Util.getTime("yyyy-MM-dd HH:mm:ss");
                break;
            case 6:
                // 自定义SQL
            case 7:
                // 流程字段转SQL
                sql = apiConfigDetailDTO.getParamValue();
                resultSql = Util.parsingSq(sql, dataMap);
                toolUtil.writeErrorLog(dataMap.toString());
                if (resultSql.contains("delete ") || resultSql.contains("update ") || resultSql.contains("exec ")
                    || resultSql.contains("drop ") || resultSql.contains("truncate ")) {
                    value = null;
                } else {
                    RecordSet rs = new RecordSet();
                    rs.executeQuery(resultSql.replace("ｓｅｌｅｃｔ", "select"));
                    rs.next();
                    value = Util.null2String(rs.getString(1));
                    toolUtil.writeErrorLog("转换值：" + value);
                    toolUtil.writeErrorLog("转换SQL：" + resultSql.replace("ｓｅｌｅｃｔ", "select"));
                }
                break;
            case 8:
                //
                // 流程名称
                value = Util.getWorkflowNameById(String.valueOf(dataMap.get("workflowid")));
                break;
            case 9:
                //
                // 请求标题
                value = Util.getRequestTitleById(String.valueOf(dataMap.get("requestid")));
                break;
            case 10:
                //
                // 流程requestId
                value = dataMap.get("requestid");
                break;
            default:
                value = null;
                break;
        }
        if (apiConfigDetailDTO.getParamType() == 1) {
            // Integer
            value = Integer.parseInt(String.valueOf(value));
        } else if (apiConfigDetailDTO.getParamType() == 2) {
            // Boolean
            value = Boolean.parseBoolean(String.valueOf(value));
        }
        return value;
    }

    public void queryContractStatus(String workflowId, String requestId, int type) {
        List<Map<String, Object>> maps = faDDServiceMapping.queryDetailInfo(requestId, workflowId, 2);
        toolUtil.writeErrorLog("maps+:" + maps);
        List<Map<String, Object>> notSignedContracts = new ArrayList<>();
        // 查询是是否签署
        for (Map<String, Object> map : maps) {
            // 发送请求查询合同信息
            Map<String, Object> data = new HashMap<>();
            String contracts = String.valueOf(map.get("contract_no"));
            if (contracts == null) {
                contracts = "";
            }
            String[] split = contracts.split(",");
            for (String s : split) {
                toolUtil.writeErrorLog(s);
                data.put("contractNo", s);
                Map<String, Object> result = null;
                // List<String> statusList = new ArrayList<>();
                try {
                    Map<String, Object> response = FaDDRequestUtils.queryContractStatus(data);
                    if (!"200".equals(response.get("code"))) {
                        throw new RuntimeException("法大大请求接口错误！");
                    }
                    result = (Map<String, Object>)response.get("data");
                    this.toolUtil.writeErrorLog("催一催：" + result);
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    throw e;
                } catch (JsonProcessingException e) {
                    toolUtil.writeDebuggerLog("转换错误：" + e);
                }
                if ("1".equals(String.valueOf(result.get("status")))
                    || "6".equals(String.valueOf(result.get("status")))) {
                    // 发送请求催一下 签署合同
                    notSignedContracts.add(map);
                } else {
                    // 合同状态发生改变，需要修改数据库中的状态信息 百分百会出问题
                    map.put("contract_status", result.get("status"));
                    // statusList.add()
                    faDDServiceMapping.updateContractStatus(map, workflowId, 3);
                }
            }
        }
        if (type == 0) {
            signedContract(workflowId, requestId, notSignedContracts);
        }
    }

    public void signedContract(String workflowId, String requestId, List<Map<String, Object>> detailMaps) {
        String mainTable = faDDServiceMapping.getMainTable(workflowId);
        RecordSet rs = new RecordSet();
        String query = "select * from " + mainTable + " where requestid = ?";
        rs.executeQuery(query, requestId);
        Map<String, Object> mainMap;
        mainMap = Util.recordSet2Map(rs);
        String mainId = "";
        if (mainMap != null) {
            mainId = String.valueOf(mainMap.get("id"));
        } else {
            toolUtil.writeErrorLog("没有查询到相关的请求id的数据！");
        }
        String detailTable1 = faDDServiceMapping.getDetailTable(workflowId, 3);
        query = "select * from " + detailTable1 + " where mainid = ?";
        rs.executeQuery(query, mainId);
        /*List<Map<String,Object>> detailMaps;
        detailMaps = Util.recordSet2MapList(rs);
        if (detailMaps == null) {
        	toolUtil.writeErrorLog("查询明细失败！maps为null");
        	return;
        }*/
        FaDaDaConfigDTO faDaDaConfigDTO = faDDServiceMapping.queryConfig(workflowId, 3);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfigTree(faDaDaConfigDTO.getParamsConfig());
        List<Map<String, Object>> dataArr = new ArrayList<>();
        String detailTable;
        String dt = detailTable1.substring(detailTable1.indexOf("_dt") + 3);
        detailTable = "detail_" + dt;
        for (Map<String, Object> detailMap : detailMaps) {
            Map<String, Object> dataMap = new HashMap<>();
            for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
                dataMap.put(detailTable + "." + entry.getKey(), entry.getValue());
            }
            for (Map.Entry<String, Object> entry : mainMap.entrySet()) {
                dataMap.put("main" + "." + entry.getKey(), entry.getValue());
            }
            dataArr.add(dataMap);
        }
        List<Map<String, Object>> maps = objectAndListHandle(apiConfigMainDTO.getDetails(), dataArr);
        for (Map<String, Object> map : maps) {
            toolUtil.writeErrorLog(map.toString());
            String contractNos = Util.null2String(map.get("contractNo"));
            String[] split = contractNos.split(",");
            for (String s : split) {
                map.put("contractNo", s);
                ResponeVo responeVo = FaDDRequestUtils.signedContract(map, apiConfigMainDTO.getApiUrl());
                Map<String, Object> response = null;
                try {
                    response = responeVo.getEntityMap();
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                if (!"200".equals(response.get("code"))) {
                    throw new RuntimeException("法大大请求接口错误！");
                }
            }
        }
    }

    public StreamingOutput contractDownload(String requestId, String workflowId) {
        toolUtil.writeErrorLog("进入service方法！");
        List<Map<String, Object>> maps = null;
        // 查询合同信息
        try {
            maps = faDDServiceMapping.queryDetailDownInfo(requestId, workflowId, 2);
        } catch (Exception e) {
            toolUtil.writeErrorLog(String.valueOf(faDDServiceMapping));
            toolUtil.writeErrorLog("调用错误" + e);
        }
        toolUtil.writeErrorLog(String.valueOf(maps));
        toolUtil.writeErrorLog(JSONObject.toJSONString(maps));
        List<Map<String, Object>> finalMaps = maps;
        String versionStringByWfid = WorkflowVersion.getVersionStringByWfid(workflowId);
        RecordSet rs = new RecordSet();
        rs.executeQuery(
            "select * from uf_contract_config where workflow_type in ( " + versionStringByWfid + " ) and api_type = ?",
            5);
        rs.next();
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfig(rs.getString("params_config"));
        return outputStream -> {
            ZipOutputStream zipOut = new ZipOutputStream(outputStream);
            toolUtil.writeErrorLog("进入方法！");
            int catchLen = 10 * 1024;
            String base = "";
            for (Map<String, Object> map : finalMaps) {
                base = base + map.get("gyshtfmczw") + "/";
                // 获取合同id
                String contractNoStr = String.valueOf(map.get("contract_no"));
                String contractNameStr = String.valueOf(map.get("file_name"));
                String[] contractNos = contractNoStr.split(",");
                String[] contractNames = contractNameStr.split(",");
                for (int i = 0; i < contractNos.length; i++) {
                    String contractNo = contractNos[i];
                    String contractName = contractNames[i];
                    Map<String, Object> data = new HashMap<>();
                    data.put("contractNo", contractNo);
                    // 下载合同
                    String finalBase = base;
                    FaDDRequestUtils.downContract(data, response -> {
                        HttpEntity entity = response.getEntity();
                        if (response.getStatusLine().getStatusCode() != 200) {
                            throw new RuntimeException("法大大请求接口错误！");
                        }
                        InputStream content = null;
                        try {
                            content = entity.getContent();
                            Header contentHeader = response.getFirstHeader("Content-disposition");
                            String filename = contractName.substring(0, contractName.indexOf(".")) + ".pdf";
                            if (contentHeader != null) {
                                HeaderElement[] values = contentHeader.getElements();
                                NameValuePair param = values[0].getParameterByName("filename");
                                filename = param.getValue();
                            }
                            zipOut.putNextEntry(new ZipEntry(finalBase + filename));
                            byte[] buffer = new byte[catchLen];
                            int len = 0;
                            while ((len = content.read(buffer)) != -1) {
                                zipOut.write(buffer, 0, len);
                            }
                            zipOut.closeEntry();
                        } catch (IOException e) {
                            e.printStackTrace();
                            toolUtil.writeErrorLog("压缩错误！" + e + "\n");
                        }
                    }, apiConfigMainDTO.getApiUrl());
                }
            }
            zipOut.flush();
            zipOut.close();
        };
    }

    public boolean isAllSinged(String requestId, String workflowId) {
        List<Map<String, Object>> maps = faDDServiceMapping.queryDetailInfo(requestId, workflowId, 2);
        if (maps == null || maps.size() == 0) {
            return true;
        }
        return false;
    }

    public boolean isSingedOneself(String requestId, String workflowId) {
        List<Map<String, Object>> maps = faDDServiceMapping.querySignedInfo(requestId, workflowId);
        if (maps == null || maps.size() == 0) {
            return false;
        }
        return true;
    }

    public void signedContractOwn(String workflowId, String requestId) {
        String mainTable = faDDServiceMapping.getMainTable(workflowId);
        RecordSet rs = new RecordSet();
        String query = "select * from " + mainTable + " where requestid = ?";
        rs.executeQuery(query, requestId);
        Map<String, Object> mainMap;
        mainMap = Util.recordSet2Map(rs);
        String mainId = "";
        if (mainMap != null) {
            mainId = String.valueOf(mainMap.get("id"));
        } else {
            toolUtil.writeErrorLog("没有查询到相关的请求id的数据！");
        }
        String detailTable1 = faDDServiceMapping.getDetailTable(workflowId, 4);
        query = "select * from " + detailTable1 + " where mainid = ?";
        rs.executeQuery(query, mainId);
        List<Map<String, Object>> detailMaps;
        detailMaps = Util.recordSet2MapList(rs);
        this.toolUtil.writeErrorLog("查询到的数据：" + detailMaps.toString());
        if (detailMaps == null) {
            toolUtil.writeErrorLog("查询明细失败！maps为null");
            return;
        }
        FaDaDaConfigDTO faDaDaConfigDTO = faDDServiceMapping.queryConfig(workflowId, 4);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfigTree(faDaDaConfigDTO.getParamsConfig());
        List<Map<String, Object>> dataArr = new ArrayList<>();
        String detailTable;
        String dt = detailTable1.substring(detailTable1.indexOf("_dt") + 3);
        detailTable = "detail_" + dt;
        toolUtil.writeErrorLog("明细表：" + detailTable);
        for (Map<String, Object> detailMap : detailMaps) {
            Map<String, Object> dataMap = new HashMap<>();
            for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
                dataMap.put(detailTable + "." + entry.getKey(), entry.getValue());
            }
            for (Map.Entry<String, Object> entry : mainMap.entrySet()) {
                dataMap.put("main" + "." + entry.getKey(), entry.getValue());
            }
            dataArr.add(dataMap);
        }
        toolUtil.writeErrorLog("替换参数值：" + dataArr.toString());
        List<Map<String, Object>> maps = objectAndListHandle(apiConfigMainDTO.getDetails(), dataArr);
        for (Map<String, Object> map : maps) {
            this.toolUtil.writeErrorLog("签署参数：" + map.toString());
            String contractNos = Util.null2String(map.get("contractNo"));
            String[] split = contractNos.split(",");
            for (String s : split) {
                map.put("contractNo", s);
                ResponeVo responeVo = FaDDRequestUtils.signedContract(map, apiConfigMainDTO.getApiUrl());
                Map<String, Object> response = null;
                try {
                    response = responeVo.getEntityMap();
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                if (!"200".equals(response.get("code"))) {
                    // throw new RuntimeException("法大大请求接口错误！");
                    this.toolUtil.writeErrorLog("签署参数：" + responeVo.getEntityString());
                }
            }
        }
    }

    public Map<String, Object> getAllVersion(String workflowId, String markOnly) {
        String versionStringByWfid = WorkflowVersion.getVersionStringByWfid(workflowId);
        String newWorkflowId = faDDServiceMapping.getAllVersion(versionStringByWfid);
        String allVersion = WorkflowVersion.getVersionStringByWfid(newWorkflowId);
        if (allVersion == null) {
            allVersion = "";
        }
        String[] split = allVersion.split(",");
        Map<String, Object> data = new HashMap<>();
        String[] nodes = this.getNodes(workflowId, markOnly);
        data.put("workflowIds", split);
        data.put("nodeIds", nodes);
        return data;
    }

    public String[] getNodes(String workflowId, String markOnly) {
        String versionStringByWfid = WorkflowVersion.getVersionStringByWfid(workflowId);
        String nods = faDDServiceMapping.getNodes(versionStringByWfid, markOnly);
        if (nods == null) {
            nods = "";
        }
        return nods.split(",");
    }
}
